package com.cui.project.service.impl;


import com.api.common.model.entity.UserInterfaceInfo;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.api.common.common.ErrorCode;
import com.cui.project.constant.RedisConstant;
import com.cui.project.exception.BusinessException;
import com.cui.project.mapper.UserInterfaceInfoMapper;
import com.cui.project.service.UserInterfaceInfoService;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
* @author 86176
* @description 针对表【user_interface_info(用户调用接口关系)】的数据库操作Service实现
* @createDate 2024-09-26 11:22:31
*/
@Service
public class UserInterfaceInfoServiceImpl extends ServiceImpl<UserInterfaceInfoMapper, UserInterfaceInfo>
    implements UserInterfaceInfoService {


    @Resource
    private RedissonClient redissonClient;

    @Override
    public void validUserInterfaceInfo(UserInterfaceInfo userInterfaceInfo, boolean add) {

        if (userInterfaceInfo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long id = userInterfaceInfo.getId();
        Long userId = userInterfaceInfo.getUserId();
        Long interfaceInfoId = userInterfaceInfo.getInterfaceInfoId();
        Integer totalNum = userInterfaceInfo.getTotalNum();
        Integer leftNum = userInterfaceInfo.getLeftNum();
        Integer status = userInterfaceInfo.getStatus();
        Date createTime = userInterfaceInfo.getCreateTime();
        Date updateTime = userInterfaceInfo.getUpdateTime();
        Integer isDelete = userInterfaceInfo.getIsDelete();


        // 创建时，所有参数必须非空
        if (add) {
            if (userId<=0||interfaceInfoId<=0 ) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"接口或用户不存在");
            }
        }
        if (leftNum<0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "剩余次数不能小于 0");
        }
    }

    /**
     * todo 这边需要加锁，分布式锁
     *
     * @param interfaceInfoId
     * @param userId
     * @return
     */
    @Override
    public int invokeCount(long interfaceInfoId, long userId) {
        // 判断(其实这里还应该校验存不存在，这里就不用校验了，因为它不存在，也更新不到那条记录)
        if (interfaceInfoId <= 0 || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //分布式锁
        String lockKey=String.format(RedisConstant.USER_INTERFACEINFO_INVOKECOUNT,userId,interfaceInfoId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            int waitTime=5;
            int expireTime=10;
            boolean locked = lock.tryLock(waitTime, expireTime, TimeUnit.SECONDS);
            if(!locked){
                throw new BusinessException(ErrorCode.SYSTEM_ERROR,"系统繁忙，请稍后重试");
            }

            // 使用 UpdateWrapper 对象来构建更新条件
            UpdateWrapper<UserInterfaceInfo> updateWrapper = new UpdateWrapper<>();
            // 在 updateWrapper 中设置了两个条件：interfaceInfoId 等于给定的 interfaceInfoId 和 userId 等于给定的 userId。
            updateWrapper.eq("interfaceInfoId", interfaceInfoId);
            updateWrapper.eq("userId", userId);
            updateWrapper.gt("leftNum", 0); // 乐观锁，防止并发超扣
            // setSql 方法用于设置要更新的 SQL 语句。这里通过 SQL 表达式实现了两个字段的更新操作：
            // leftNum=leftNum-1和totalNum=totalNum+1。意思是将leftNum字段减一，totalNum字段加一。
            updateWrapper.setSql("leftNum = leftNum - 1, totalNum = totalNum + 1");
            // 最后，调用update方法执行更新操作，并返回更新是否成功的结果
            if(! this.update(updateWrapper)){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"调用次数扣减失败");
            }
            return 1; // 返回成功扣减的次数
        }catch (InterruptedException e){
            Thread.currentThread().interrupt();
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"锁获取失败");
        }finally {
            //释放锁
            if(lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }

    }



}




